package com.stars.aspect;

import com.stars.common.MyReflectionUtils;
import com.stars.common.MyStrRegex;
import com.stars.common.annotation.Dict;
import com.stars.common.annotation.DictClass;
import com.stars.common.annotation.DictUpdate;
import com.stars.common.base.ResultMsg;
import com.stars.common.cons.RedisCons;
import com.stars.common.maps.JsonToMapUtils;
import com.stars.common.maps.JsonUtils;
import com.stars.services.sysdict.SysDictAccessServices;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName DictAspect
 * @Description: 字典切面
 * @Author DJ
 * @Date 2019/10/24
 * @Version V1.0
 **/
@Aspect
@Component
public class DictAspect {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private SysDictAccessServices sysDictAccessServicesImpl;
    private static final String DICT_TABLE ="dictTable";
    private static final String DICT_CODE ="dictCode";
    private static final String DICT_TEXT ="dictText";
    private static final String DICT_NAME ="dictName";
    private static final String DICT_SOURCE ="dictSource";
    //用于使用字典的方法上
    @Pointcut("@annotation(dictClass)")
    public void doDataDictClass(DictClass dictClass) {
    }

    //用户监听字典更新状态
    @Pointcut("@annotation(dictUpdate)")
    public void dictUpdate(DictUpdate dictUpdate) {
    }

    /**
     * 字典更新时，也更新Redis
     *
     * @param joinPoint
     * @param dictUpdate
     * @return
     * @throws Throwable
     */
    @Around("@annotation(dictUpdate)")
    public Object doUpdateDict(ProceedingJoinPoint joinPoint, DictUpdate dictUpdate) throws Throwable {
        Object res = joinPoint.proceed();
        if (null == res) {
            return null;
        }
        if (dictUpdate != null && dictUpdate.dict()) {
            String jsonStr = JsonUtils.objectToJson(res);
            ResultMsg resultMsg = JsonUtils.jsonToPojo(jsonStr, ResultMsg.class);
            if (null != resultMsg && resultMsg.isSuccess()) {
                Map<String, Object> dictToMap = sysDictAccessServicesImpl.findDictToMap();
                stringRedisTemplate.opsForValue().set(RedisCons.USER_DICT, JsonToMapUtils.mapToJson(dictToMap), 1, TimeUnit.DAYS);
            }
        }
        return res;
    }

    @Around("@annotation(dictClass)")
    public Object translation(final ProceedingJoinPoint pjp, DictClass dictClass) throws Throwable {
        Object result = pjp.proceed();
        if (result == null) {
            return result;
        }
        Object obj;
        if (result instanceof List || result instanceof ArrayList) {
            List oList = ((List) result);
            if (oList.size() == 0) {
                return result;
            }
            obj = oList.get(0);
        } else {
            obj = result;
        }
        List<Map<String, String>> dictParams = boDict(obj.getClass());
        if (dictParams.size() == 0) {
            return result;
        }
        String jsonStr = stringRedisTemplate.opsForValue().get(RedisCons.USER_DICT);
        if (StringUtils.isBlank(jsonStr)) {
            Map<String, Object> dictToMap = sysDictAccessServicesImpl.findDictToMap();
            stringRedisTemplate.opsForValue().set(RedisCons.USER_DICT, JsonToMapUtils.mapToJson(dictToMap), 1, TimeUnit.DAYS);
            jsonStr = stringRedisTemplate.opsForValue().get(RedisCons.USER_DICT);
        }
        Map<String, Object> dictMap = JsonToMapUtils.jsonToMapJSONObject(jsonStr);

        if (result instanceof List || result instanceof ArrayList) {
            for (Object o : (List) result) {
                sign(o, dictParams, dictMap);
            }
        } else {
            sign(result, dictParams, dictMap);
        }
        return result;
    }

    /**
     * 单个设置值
     *
     * @param obj
     * @param dictParams
     * @param dictInfoMap
     */
    public void sign(Object obj, List<Map<String, String>> dictParams, Map<String, Object> dictInfoMap) {

        for (Map<String, String> dictParam : dictParams) {
            String dict = dictParam.get(DICT_TEXT);
            String dictTable = dictParam.get(DICT_TABLE);
            String dictTableId = dictParam.get(DICT_CODE);
            String dictName = dictParam.get(DICT_NAME);
            String dictSource = dictParam.get(DICT_SOURCE);
            try {
                //获取源编码值
                String sourceValue = (String) MyReflectionUtils.getFieldValue(obj, dictSource);
                if (StringUtils.isBlank(sourceValue)) {
                    return;
                }
                String dictCodeName = "";
                //如果通过表查询
                if (StringUtils.isNotBlank(dictTable)) {
                    String tableDictRedisId =RedisCons.USER_DICT + dictTable.toUpperCase()+dict.toUpperCase();
                    String jsonStr = stringRedisTemplate.opsForValue().get(tableDictRedisId);
                    Map<String, Object> dictMap = JsonToMapUtils.jsonToMapJSONObject(jsonStr);
                    if(null == dictMap){
                        Map<String, Object> dictTableToMap = sysDictAccessServicesImpl.findDictTableToMap(dictTable,dictTableId, dict);
                        stringRedisTemplate.opsForValue().set(tableDictRedisId, JsonToMapUtils.mapToJson(dictTableToMap), 1, TimeUnit.DAYS);
                        jsonStr = stringRedisTemplate.opsForValue().get(tableDictRedisId);
                        dictMap = JsonToMapUtils.jsonToMapJSONObject(jsonStr);
                    }
                    Object objName =dictMap.get(sourceValue);
                    if(null == objName){
                        Map<String, Object> dictTableToMap = sysDictAccessServicesImpl.findDictTableToMap(dictTable,dictTableId, dict);
                        stringRedisTemplate.opsForValue().set(tableDictRedisId, JsonToMapUtils.mapToJson(dictTableToMap), 1, TimeUnit.DAYS);
                        jsonStr = stringRedisTemplate.opsForValue().get(tableDictRedisId);
                        Map<String, Object> dictMap2 = JsonToMapUtils.jsonToMapJSONObject(jsonStr);
                        if(null != dictMap2.get(sourceValue)){
                            dictCodeName = dictMap2.get(sourceValue).toString();
                        }
                    }else {
                        dictCodeName = objName.toString();
                    }
                } else {
                    dictCodeName = dictInfoMap.get(dictTableId + sourceValue).toString();
                }
                //设置值
                MyReflectionUtils.setFieldValue(obj, dictName, dictCodeName);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }


    }

    /**
     * 获取bo中属性值
     *
     * @param cla
     * @return
     */
    private List<Map<String, String>> boDict(Class cla) {
        Field[] fields = cla.getDeclaredFields();
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map;
        Dict dict;
        for (Field field : fields) {
            if (field.isAnnotationPresent(Dict.class)) {
                map = new HashMap<>();
                dict = field.getAnnotation(Dict.class);
                map.put(DICT_TEXT, dict.dictName());
                map.put(DICT_TABLE, dict.dictTable());
                map.put(DICT_CODE, dict.dictCode());
                map.put(DICT_SOURCE, MyStrRegex.underLineBackFirstCharToUpperCase(dict.dictSource()));
                map.put(DICT_NAME, field.getName());
                list.add(map);
            }
        }
        return list;
    }


}
